package com.nec.recommend.module.weapp.controller;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nec.recommend.auth.AuthUser;
import com.nec.recommend.auth.WeappProp;
import com.nec.recommend.common.PageEntity;
import com.nec.recommend.common.TreeNode;
import com.nec.recommend.config.annotation.WeappApi;
import com.nec.recommend.exception.ServiceException;
import com.nec.recommend.module.system.dto.TokenInfoDTO;
import com.nec.recommend.module.weapp.dto.WeappRecommendDTO;
import com.nec.recommend.module.weapp.dto.WeappRecommendUserDTO;
import com.nec.recommend.module.weapp.dto.WeappScoreDTO;
import com.nec.recommend.module.weapp.dto.WeappUserDTO;
import com.nec.recommend.module.weapp.entity.*;
import com.nec.recommend.module.weapp.service.*;
import com.nec.recommend.module.weapp.vo.WeappGetPhoneVO;
import com.nec.recommend.module.weapp.vo.WeappGetTokenVO;
import com.nec.recommend.module.weapp.vo.WeappUserVO;
import com.nec.recommend.utils.AuthUserUtils;
import com.nec.recommend.utils.WeappUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.hibernate.validator.constraints.Length;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Api(tags = "小程序用户相关接口")
@Validated
@RestController
@RequestMapping("/weapp/user")
public class WeappUserController {
    private final WeappLoginService weappLoginService;
    private final WeappUserService weappUserService;
    private final WeappRecommendService weappRecommendService;
    private final WeappCarInfoService weappCarInfoService;
    private final WeappScoreService weappScoreService;
    private final WeappConfigService weappConfigService;
    private final WeappProp weappProp;
    private final RedisTemplate<String, Object> redisTemplate;


    public WeappUserController(WeappLoginService weappLoginService, WeappUserService weappUserService, WeappRecommendService weappRecommendService, WeappCarInfoService weappCarInfoService, WeappScoreService weappScoreService, WeappConfigService weappConfigService, WeappProp weappProp, @Qualifier("customRedisTemplate") RedisTemplate<String, Object> redisTemplate) {
        this.weappLoginService = weappLoginService;
        this.weappUserService = weappUserService;
        this.weappRecommendService = weappRecommendService;
        this.weappCarInfoService = weappCarInfoService;
        this.weappScoreService = weappScoreService;
        this.weappConfigService = weappConfigService;
        this.weappProp = weappProp;
        this.redisTemplate = redisTemplate;
    }

    @WeappApi
    @GetMapping("/login")
    @ApiOperation("登录")
    public TokenInfoDTO login(@NotBlank(message = "code不能为空") String code) {
        return weappLoginService.login(code);
    }

    @WeappApi
    @GetMapping("/phone")
    @ApiOperation("获取手机号")
    public String phone(@NotBlank(message = "code不能为空") String code) {
        String access_token = WeappUtil.getToken(new WeappGetTokenVO(weappProp.getAppid(), weappProp.getSecret()));
        WeappGetPhoneResult phoneResult = WeappUtil.getPhone(new WeappGetPhoneVO(access_token, code));
        return phoneResult.getPurePhoneNumber();
    }

    @WeappApi
    @ApiOperation("获取当前用户的基本信息")
    @GetMapping("/getCurrentUserInfo")
    public WeappUserDTO getCurrentUserInfo() {
        WeappUser weappUser = weappUserService.getOne(Wrappers.lambdaQuery(WeappUser.class).select(WeappUser::getName, WeappUser::getAvatar, WeappUser::getPhone, WeappUser::getCityName, WeappUser::getProvinceName, WeappUser::getScore, WeappUser::getMaxScore, WeappUser::getSex, WeappUser::getType, WeappUser::getCityCode, WeappUser::getProvinceCode).eq(WeappUser::getId, AuthUserUtils.getUserId()));
        if (Objects.nonNull(weappUser)) {
            WeappUserDTO weappUserDTO = BeanUtil.copyProperties(weappUser, WeappUserDTO.class);
            Integer amountScoreRate = getAmountScoreRateConfig();
            weappUserDTO.setAmount(BigDecimal.valueOf(weappUserDTO.getScore()).divide(new BigDecimal(amountScoreRate), 2, RoundingMode.HALF_UP));
            return weappUserDTO;
        }
        return null;
    }

    private Integer getAmountScoreRateConfig() {
        WeappConfig weappConfig = weappConfigService.getById("amount_score_rate");
        if (Objects.nonNull(weappConfig)) {
            return weappConfig.getValue();
        }
        throw new ServiceException("未找到金额和积分的汇率配置，请联系管理员");
    }

    @WeappApi
    @ApiOperation("获取分享id")
    @GetMapping("/getShareId")
    public String getShareId() {
        String shareId = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 24);
        AuthUser user = AuthUserUtils.getUser();
        WeappRecommendUserDTO userDTO = new WeappRecommendUserDTO();
        userDTO.setShareId(shareId);
        userDTO.setUserId(user.getId());
        userDTO.setName(user.getName());
        userDTO.setAvatar(user.getAvatar());
        userDTO.setRecommendTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        redisTemplate.opsForValue().set("shareIds:" + shareId, userDTO);
        return shareId;
    }

    @WeappApi
    @ApiOperation("获取推荐人用户信息")
    @GetMapping("/getRecommendUserInfo")
    public WeappRecommendUserDTO getRecommendUserInfo(@NotBlank(message = "分享id不能为空") String shareId) {
        Object recommendUserObj = redisTemplate.opsForValue().get("shareIds:" + shareId);
        if (Objects.isNull(recommendUserObj)) {
            throw new ServiceException("分享链接已失效");
        }
        WeappRecommendUserDTO recommendUser = (WeappRecommendUserDTO) recommendUserObj;
        Long userId = AuthUserUtils.getUserId();
        validRecommend(recommendUser.getUserId(), userId);
        // 查询待本次推荐被推荐人是自己推荐记录
        WeappRecommend recommend = weappRecommendService.getOne(Wrappers.lambdaQuery(WeappRecommend.class).eq(WeappRecommend::getUserId, recommendUser.getUserId()).eq(WeappRecommend::getReceivedUserId, userId));
        if (Objects.isNull(recommend)) {
            boolean savaFlag = weappRecommendService.saveRecommend(recommendUser);
            if (!savaFlag) {
                throw new ServiceException("获取推荐人信息失败");
            }
        }
        if (recommend.getStatus() == 2) {
            throw new ServiceException("您已经被该用户推荐过了");
        }
        return recommendUser;
    }


    private void validRecommend(Long recommendUserId, Long userId) {
        AuthUser authUser = AuthUserUtils.getUser();
        if (!weappProp.getShareSelf() && recommendUserId.equals(userId)) {
            throw new ServiceException("无法推荐给自己");
        }
        if (recommendUserId.equals(authUser.getRecommendUserId())) {
            throw new ServiceException("您已经被该用户推荐过了");
        }
    }

    @WeappApi
    @ApiOperation("提交推荐链接填写的信息")
    @PostMapping("/submitUserInfo")
    public boolean submitUserInfo(@RequestBody @Valid WeappUserVO weappUserVO) {
        Object userInfoObj = redisTemplate.opsForValue().get("shareIds:" + weappUserVO.getShareId());
        if (Objects.isNull(userInfoObj)) {
            throw new ServiceException("分享链接已失效");
        }
        WeappRecommendUserDTO recommendUser = (WeappRecommendUserDTO) userInfoObj;
        Long userId = AuthUserUtils.getUserId();
        validRecommend(recommendUser.getUserId(), userId);
        // 查询当前用户此分享id的推荐记录是否已经存在推荐成功的
        WeappRecommend recommend = weappRecommendService.getOne(Wrappers.lambdaQuery(WeappRecommend.class).eq(WeappRecommend::getStatus, 1).eq(WeappRecommend::getShareId, weappUserVO.getShareId()).eq(WeappRecommend::getUserId, userId));
        // 如果大于0则直接返回true而不创建新的记录，不影响父级业务继续进行
        if (Objects.nonNull(recommend)) {
            throw new ServiceException("该分享链接您已经成功提交过了");
        }
        return weappRecommendService.submitUserInfo(recommendUser, weappUserVO);
    }

    @WeappApi
    @ApiOperation("获取积分变动记录")
    @GetMapping("/getScoreRecords")
    public IPage<WeappScoreDTO> getScoreRecords(@Valid PageEntity pageEntity) {
        Page<WeappScore> page = new Page<>(pageEntity.getPage(), pageEntity.getLimit());
        Page<WeappScore> recommendPage = weappScoreService.page(page, Wrappers.lambdaQuery(WeappScore.class).eq(WeappScore::getUserId, AuthUserUtils.getUserId()).orderByDesc(WeappScore::getCreateTime));
        return recommendPage.convert(WeappScore::toDTO);
    }

    @WeappApi
    @ApiOperation("获取推荐记录")
    @GetMapping("/getRecommendRecords")
    public IPage<WeappRecommendDTO> getRecommendRecords(@Valid PageEntity pageEntity) {
        Page<WeappRecommend> page = new Page<>(pageEntity.getPage(), pageEntity.getLimit());
        Page<WeappRecommend> recommendPage = weappRecommendService.page(page, Wrappers.lambdaQuery(WeappRecommend.class).eq(WeappRecommend::getUserId, AuthUserUtils.getUserId()).orderByDesc(WeappRecommend::getCreateTime));
        return recommendPage.convert(WeappRecommend::toDTO);
    }

    @WeappApi
    @ApiOperation("更新用户姓名")
    @PostMapping("/updateUserName")
    public Boolean updateUserName(@RequestParam("name") @NotBlank(message = "姓名不能为空") @Length(min = 2, max = 10, message = "姓名长度需要在2位到10位之间") String name) {
        WeappUser weappUser = new WeappUser();
        weappUser.setId(AuthUserUtils.getUserId());
        weappUser.setName(name);
        boolean updateFlag = weappUserService.updateById(weappUser);
        if (updateFlag) {
            AuthUser authUser = AuthUserUtils.getUser();
            authUser.setName(name);
            weappUserService.refreshUserInfo(authUser);
        }
        return updateFlag;
    }

    @WeappApi
    @ApiOperation("获取车型信息树")
    @GetMapping("/getCarInfoTree")
    public List<TreeNode> getCarInfoTree() {
        List<WeappCarInfo> carInfoList = weappCarInfoService.list(Wrappers.lambdaQuery(WeappCarInfo.class).eq(WeappCarInfo::getStatus, 1).orderByAsc(WeappCarInfo::getSortValue));
        Map<String, List<WeappCarInfo>> groupListMap = carInfoList.stream().collect(Collectors.groupingBy(carInfo -> carInfo.getCarBrand() + "|" + carInfo.getCarBrandCode()));
        List<TreeNode> treeNodeList = new ArrayList<>();
        for (Map.Entry<String, List<WeappCarInfo>> entry : groupListMap.entrySet()) {
            TreeNode parentNode = new TreeNode();
            String key = entry.getKey();
            String[] strArr = key.split("\\|");
            parentNode.setText(strArr[0]);
            parentNode.setValue(strArr[1]);
            parentNode.setChildren(entry.getValue().stream().map(carInfo -> {
                TreeNode childNode = new TreeNode();
                childNode.setText(carInfo.getCarType());
                childNode.setValue(carInfo.getCarTypeCode());
                return childNode;
            }).collect(Collectors.toList()));
            treeNodeList.add(parentNode);
        }
        return treeNodeList;
    }

}
